package com.meevle.utilities;

import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Required;

public class HibernateManager {
	private Object identity;
	/** Read the configuration, will share across threads**/
	  private SessionFactory sessionFactory;
	  private SessionFactory annotatedSessionFactory;
	  
	  /** the per thread session **/
//	  private final ThreadLocal currentSession = new ThreadLocal();
	  private Session currentSession;
	  /** The constants for describing the ownerships **/
	  private final Owner trueOwner = new Owner(true);
	  private final Owner fakeOwner = new Owner(false);
	  
	  private volatile static HibernateManager instance = null;
		
		private HibernateManager()
		{}
		
		public static HibernateManager getInstance ()
		{
	        if (instance == null)
	        {
	        	synchronized (HibernateManager.class)
	        	{
	        		if (instance == null)
	        			{
	        				instance = new HibernateManager ();
	        			}
				}
	        }
	        return instance;
	    }
	  
		
		
	  /**
	   * get the hibernate session and set it on the thread local. Returns trueOwner if 
	   * it actually opens a session
	   */
	  public Object createSession() throws Exception{
//	    Session session = (Session)currentSession.get();  
	    Session session = currentSession;
		  System.out.println(session);
	    if(session == null){
	      System.out.println("No Session Found - Create and give the identity");
	      
	      session = getSessionFactory().openSession(); 
//	      currentSession.set(session);
	      currentSession = session;
	      return trueOwner;
	    }
	    System.out.println("Session Found - Give a Fake identity");
	    return fakeOwner;
	  }
	  /**
	   * The method for closing a session. The close  and flush 
	   * will be executed only if the session is actually created
	   * by this owner.  
	   */
	  public void closeSession(Object ownership) throws Exception{
	    if(((Owner)ownership).identity){
	      System.out.println("Identity is accepted. Now closing the session");
//	      Session session = (Session)currentSession.get();
//	      session.flush();
//	      session.close();
//	      currentSession.set(null);
	      currentSession.flush();
	      currentSession.close();
	      currentSession = null;
	    }else {
	       System.out.println("Identity is rejected. Ignoring the request");
	    }
	  }  
	  /**
	   * returns the current session
	   */
	  public Session getSession() throws HibernateException {
//	    return ((Session)currentSession.get()==null?annotatedSessionFactory.openSession():(Session)currentSession.get());
		  return currentSession;
	  } 
	  /** 
	   * Creating a session factory , if not already loaded
	   */
	  private SessionFactory getSessionFactory() 
	                          throws HibernateException {
	    try {
	      if(sessionFactory == null){
	    	  sessionFactory = annotatedSessionFactory;
	      } 
	       return sessionFactory;
	    }catch (Exception e){
	      throw new HibernateException("Error getting Factory");
	    }
	  }  
	 
	  /**
	   * Internal class , for handling the identity. Hidden for the 
	   * developers
	   */
	  private static class Owner {
	     public Owner(boolean identity){
	      this.identity = identity;
	     }
	     boolean identity = false;        
	  }

	public SessionFactory getAnnotatedSessionFactory() {
		return annotatedSessionFactory;
	}
	
	@Required
	public void setAnnotatedSessionFactory(SessionFactory annotatedSessionFactory) {
		this.annotatedSessionFactory = annotatedSessionFactory;
		this.sessionFactory = annotatedSessionFactory;
		System.out.println("\nAnnotsessfact: " + annotatedSessionFactory);
	}

	public void init()
	{
		identity = null;
		try {
			System.out.println("\nHibernateManagerInstance: " + HibernateManager.getInstance());
			
			HibernateManager.getInstance().setAnnotatedSessionFactory(annotatedSessionFactory);
			identity = HibernateManager.getInstance().createSession();
		} catch (Exception e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
	}
	
	public void destroy()
	{
		try {
			HibernateManager.getInstance().closeSession(identity);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	  

}